package pcomponents;

import java.util.Random;
import java.io.Serializable;

/**
 * The Operator Software, used to detect faults in the software.
 * Holds a simple boolean value, that plant controller checks when a command
 * is executed.
 * Because the maximum number of OperatorSoftwares is 1, it handles failure 
 * itself.
 * @author bjw523
 */
public class OperatorSoftware implements Serializable{          
    private final static int DEFAULT_FAILURE_RATE = 10;
   // private final static int MAX_FAILURE_RATE = 50;
    private final static int MIN_FAILURE_RATE = 5;
    private final static boolean DEFAULT_OPERATIONAL = true;
    private final static int DEFAULT_TIME_FAILING = 10;
    
    private int failureRate;
    private int maxFailureRate;
    private int minFailureRate;
    private boolean operational;
    private Random random = new Random();
    private int timeFailing;
    private int remainingTimeFailing;

    /**
     * Default Constructor. Initialises all failure variables to their default.
     */
    public OperatorSoftware() {
        this(DEFAULT_FAILURE_RATE, DEFAULT_OPERATIONAL, DEFAULT_TIME_FAILING);
    }

    /**
     * Constructor to set up an OperatorSoftware with different failure
     * variables
     * @param failureRate int, compared against a random between 1-1000
     * @param operational boolean, whether the plant starts up faulty
     * @param timeFailing int, the amount of time the software fails for when it fails
     */
    public OperatorSoftware(int failureRate, boolean operational, int timeFailing) {
        this.failureRate = failureRate;
     //   this.maxFailureRate = MAX_FAILURE_RATE;
        this.minFailureRate = MIN_FAILURE_RATE;
        this.operational = operational;
        this.timeFailing = timeFailing;
        this.remainingTimeFailing = 0;
    }

    /**
     * Gets failure rate
     * @return failure rate
     */
    public int getFailureRate() {
        return failureRate;
    }

    /**
     * Sets the failure rate (as long as the value is in the acceptable range)
     * @param failureRate 
     */
    public void setFailureRate(int failureRate) {
        if (failureRate >= minFailureRate) {
            this.failureRate = failureRate;
        } else {
            this.failureRate = minFailureRate;
        }
    }

    /**
     * Gets whether the Operator Software is failing
     * @return false if the software is failing
     */
    public boolean isOperational() {
        return operational;
    }

    /**
     * When called generates a Software failure with chance failureRate / 1000
     */
    public void checkInoperable() {
        int checkFailure = random.nextInt(1000);
        if (failureRate >= checkFailure) {
            this.remainingTimeFailing = timeFailing;
            this.operational = false;
        }
    }
    
    /**
     * When called, if the Software is currently failing, decrements the remaining 
     * time for failure.
     */
    public void update() {
        if (!operational) {
            if (remainingTimeFailing > 0) {
                remainingTimeFailing -= 1;
            } else {
                this.operational = true;
            }
        }
    }
    
    /*
     * ------------------------------------------------------------------------
     * Testing Functions
     */
    
     /**
     * TODO
     * @param checkFailure 
     */
    public void checkInoperableTest(int checkFailure) {
        if (failureRate >= checkFailure) {
            this.remainingTimeFailing = timeFailing;
            this.operational = false;
        }
    }
}
